package org.tcshare.widgets;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.Nullable;

/**
 * @author 爱T鱼
 * @date 2021年1月5日
 */
public class GaugeView extends View {
    protected int bgRound1 = Color.parseColor("#99122a73");
    protected int bgRound2 = Color.parseColor("#66122a73");
    protected int bgRound3 = Color.parseColor("#22142f80");
    protected int bgRound4 = Color.parseColor("#0e2267");
    protected int circle1 = Color.parseColor("#0d1d4c");
    protected int bgRadius1;
    protected int bgRadius2;
    protected int bgRadius3;
    protected int bgRadius4;
    protected int circleRadius1;
    protected int circleRadius2;

    // 背景圆画笔
    protected Paint roundPaint;
    protected int mWidth;
    protected int mHeight;
    protected int mCx;
    protected int mCy;
    protected int radius;
    // 刻度画笔
    protected Paint pointerPaint;
    protected float textSizeDial = 14; // 刻度字体大小
    protected Paint.FontMetrics pointerFontMetrics;
    // 标题画笔
    protected Paint labelPaint;
    // 长刻度线半径
    protected int radiusDial;
    protected float maxVal = 150f;
    protected float minVal = -50f;

    protected int lowDialLimit = 20; // 低段温度警戒线
    protected int highDialLimit = 80; // 中段警戒线
    protected int colorDialLower = Color.parseColor("#00faff"); // 低中高三个色段表盘刻度
    protected int colorDialMiddle = Color.GREEN;
    protected int colorDialHigh = Color.RED;

    protected int lengthLDial = 16;// 长刻度线的长度
    protected int lengthSDial = 8;// 短刻度线的长度
    protected float strokeLDial = 3;
    protected float strokeSDial = 1;
    protected float circleRadius1StrokeWidth = 2f;
    protected float circleRadius2StrokeWidth = 4f;
    protected float pointerLineDegree = 135; // 多少角度
    protected float arcStartDegree = pointerLineDegree; // 弧线起始角度
    protected Paint valPaint;

    protected Paint.FontMetrics labelFontMetrics;
    protected Paint.FontMetrics valFontMetrics;
    protected String valText="";
    protected float realVal; // 真实的值
    protected float valTextSize = 40f;// 值字体大小
    protected int valTextColor = Color.WHITE;// 值字体颜色
    protected String labelText ="";
    protected float labelTextSize = 20f;// 标签字体
    protected int labelTextColor = Color.WHITE;// 标签字体颜色
    protected Paint arcPaint;
    protected RectF mArcRect, mCircleArcRect1,mCircleArcRect2; // 指针（半扇形）及描边线
    protected float arcPaintStrokeWidth = 2f; // 描边宽度
    protected int arcColor = Color.parseColor("#ff8e00");
    protected int colors[] = new int[]{Color.TRANSPARENT,Color.TRANSPARENT, Color.TRANSPARENT, arcColor };
    protected int colorsArcLine[] = new int[]{ arcColor,arcColor,Color.TRANSPARENT };
    protected Shader arcShader;
    protected Shader arcLineShader;
    protected float sweepAngle = 0;
    protected String formatter = "%.0f";
    protected int drawDialNum = 100;
    protected int dialStep = 10; // 分度
    protected float valRange;
    protected float stepDegree;
    protected float sRoateDegree;


    public GaugeView(Context context) {
        super(context);
        init();
    }


    public GaugeView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public GaugeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public GaugeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }


    protected void init() {
        // 初始化圆背景画笔
        roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        // 扫描扇
        arcPaint = new Paint();
        arcPaint.setAntiAlias(true);


        // 刻度
        pointerPaint = new Paint();
        pointerPaint.setAntiAlias(true);
        pointerPaint.setTextSize(textSizeDial);
        pointerPaint.setTextAlign(Paint.Align.CENTER);
        pointerFontMetrics = pointerPaint.getFontMetrics();

        // 标题
        labelPaint = new Paint();
        labelPaint.setAntiAlias(true);
        labelPaint.setTextAlign(Paint.Align.CENTER);
        labelPaint.setFakeBoldText(true);
        labelPaint.setTextSize(labelTextSize);
        labelPaint.setColor(labelTextColor);
        labelFontMetrics = labelPaint.getFontMetrics();

        // 值
        valPaint = new Paint();
        valPaint.setAntiAlias(true);
        valPaint.setTextAlign(Paint.Align.CENTER);
//        valPaint.setFakeBoldText(true);
        valPaint.setTextSize(valTextSize);
        valPaint.setColor(valTextColor);
        valFontMetrics = valPaint.getFontMetrics();

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawBG(canvas);
        drawArc(canvas);
        drawPointerLine(canvas);
        drawValText(canvas);
        drawLabelText(canvas);

    }
    private void drawArc(Canvas canvas){
        canvas.save();
        arcPaint.setStyle(Paint.Style.FILL);
        arcPaint.setShader(arcShader);
        canvas.drawArc(mArcRect, arcStartDegree, sweepAngle, true, arcPaint);

        arcPaint.setStyle(Paint.Style.STROKE);
        arcPaint.setColor(arcColor);
        arcPaint.setShader(null);
        arcPaint.setStrokeWidth(arcPaintStrokeWidth);
        canvas.drawArc(mArcRect, arcStartDegree, sweepAngle, false, arcPaint);

        arcPaint.setStrokeWidth(arcPaintStrokeWidth);
        canvas.drawArc(mCircleArcRect1, arcStartDegree, sweepAngle, false, arcPaint);
        canvas.drawArc(mCircleArcRect2, arcStartDegree, sweepAngle, false, arcPaint);

        arcPaint.setStrokeWidth(arcPaintStrokeWidth);
//        arcPaint.setShader(arcLineShader);
        canvas.translate(mCx, mCy);
        canvas.rotate(arcStartDegree + sweepAngle);
        canvas.drawLine(radiusDial, 0, circleRadius2, 0, arcPaint);
        canvas.restore();
    }
    private void drawLabelText(Canvas canvas) {
        canvas.save();
        canvas.translate(mCx, mCy +  (bgRadius3 + circleRadius1) / 2f);
        int textBaseLine = (int) (0 + (labelFontMetrics.bottom - labelFontMetrics.top) / 2 - labelFontMetrics.bottom);
        canvas.drawText(labelText, 0, textBaseLine, labelPaint);
        canvas.restore();
    }

    private void drawValText(Canvas canvas) {
        if(valText != null) {
            canvas.save();
            canvas.translate(mCx, mCy);
            int textBaseLine = (int) (0 + (valFontMetrics.bottom - valFontMetrics.top) / 2 - valFontMetrics.bottom);
            canvas.drawText(valText, 0, textBaseLine, valPaint);
            canvas.restore();
        }
    }

    private void drawPointerLine(Canvas canvas){
        canvas.save();
        canvas.translate(mCx, mCy);
        canvas.rotate(pointerLineDegree);

        for (int i=0; i<=valRange; i++){

            if (i < lowDialLimit){
                pointerPaint.setColor(colorDialLower);
            }else if (i<= highDialLimit){
                pointerPaint.setColor(colorDialMiddle);
            }else {
                pointerPaint.setColor(colorDialHigh);
            }

            if (i % dialStep == 0){     //长表针
                pointerPaint.setStrokeWidth(strokeLDial);
                canvas.drawLine(radiusDial, 0, radiusDial - lengthLDial, 0, pointerPaint);

                String text = String.format("%.0f", minVal + i);
                drawPointerText(canvas, text, i);
            }else {    //短表针
                pointerPaint.setStrokeWidth(strokeSDial);
                int offset = (lengthLDial - lengthSDial) / 2;
                canvas.drawLine(radiusDial - offset, 0, radiusDial - lengthSDial, 0, pointerPaint);
            }
            canvas.rotate(sRoateDegree);
        }
        canvas.restore();
    }

    private void drawPointerText(Canvas canvas, String text, int i){
        canvas.save();

        int currentCenterX = (int) (radiusDial - lengthLDial - strokeLDial - pointerPaint.measureText(String.valueOf(text)) / 2);
        canvas.translate(currentCenterX, 0);
        canvas.rotate(360 - pointerLineDegree -  i * sRoateDegree);

        int textBaseLine = (int) (0 + (pointerFontMetrics.bottom - pointerFontMetrics.top) /2 - pointerFontMetrics.bottom);

        canvas.drawText(text, 0, textBaseLine, pointerPaint);
        canvas.restore();
    }


    private void drawBG(Canvas canvas) {
        canvas.save();
        roundPaint.setStyle(Paint.Style.FILL);
        roundPaint.setColor(bgRound1);
        roundPaint.setStrokeWidth(0);
        canvas.drawCircle(mCx, mCy, bgRadius1, roundPaint);
        roundPaint.setColor(bgRound2);
        canvas.drawCircle(mCx, mCy, bgRadius2, roundPaint);
        roundPaint.setColor(bgRound3);
        canvas.drawCircle(mCx, mCy, bgRadius3, roundPaint);
        roundPaint.setColor(bgRound4);
        canvas.drawCircle(mCx, mCy, bgRadius4, roundPaint);
        roundPaint.setColor(circle1);
        roundPaint.setStyle(Paint.Style.STROKE);
        roundPaint.setStrokeWidth(circleRadius1StrokeWidth);
        canvas.drawCircle(mCx, mCy, circleRadius1, roundPaint);
        roundPaint.setStrokeWidth(circleRadius2StrokeWidth);
        canvas.drawCircle(mCx, mCy, circleRadius2, roundPaint);
        canvas.restore();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 获取控件区域宽高
        if (mWidth == 0 || mHeight == 0) {
            int minimumWidth = getSuggestedMinimumWidth();
            int minimumHeight = getSuggestedMinimumHeight();
            mWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
            mHeight = resolveMeasured(heightMeasureSpec, minimumHeight);
            // 获取x/y轴中心点
            mCx = mWidth / 2;
            mCy = mHeight / 2;
            radius = Math.min(mWidth, mHeight) /2;
            bgRadius1 = radius;
            bgRadius2 = (int) (radius * 0.95f);
            bgRadius3 = (int) (radius * 0.88f);
            bgRadius4 = (int) (radius * 0.6f);
            circleRadius1 = (int) (radius * 0.64f);
            circleRadius2 = (int) (radius * 0.62f);

            // 长刻度线
            radiusDial = bgRadius3;

            mArcRect = new RectF(mCx - radiusDial, mCy - radiusDial, mCx + radiusDial, mCy + radiusDial);
            mCircleArcRect1 = new RectF(mCx - circleRadius1, mCy - circleRadius1, mCx + circleRadius1, mCy + circleRadius1);
            mCircleArcRect2 = new RectF(mCx - circleRadius2, mCy - circleRadius2, mCx + circleRadius2, mCy + circleRadius2);
            arcShader = new RadialGradient(mCx, mCy, bgRadius2, colors, null, Shader.TileMode.REPEAT);
            arcLineShader = new LinearGradient(radiusDial, 0, circleRadius2,0, colorsArcLine, null, Shader.TileMode.REPEAT);
        }
    }


    /**
     *
     * @param formatter
     * @param maxVal
     * @param minVal
     * @param dialStep 必须能被最大范围整除 (maxVal - minVal) / dialStep = 0
     * @param lowDialLimit
     * @param highDialLimit
     */
    public void init(String formatter, float maxVal, float minVal,int dialStep, int lowDialLimit, int highDialLimit){
        this.dialStep = dialStep;
        float drawDegree = (360 - (180 - pointerLineDegree) * 2);
        this.maxVal = maxVal;
        this.minVal = minVal;
        this.valRange = maxVal - minVal;
        this.formatter = formatter;
        this.drawDialNum = (int) Math.ceil(valRange / dialStep);
        this.stepDegree =  drawDegree / drawDialNum;
        this.lowDialLimit = (int) (lowDialLimit - minVal);
        this.highDialLimit = (int) (highDialLimit - minVal);
        this.sRoateDegree = stepDegree/dialStep; // 短刻度旋转角度
        invalidate();
    }
    public void updateVal(float val){
        realVal = Math.max(Math.min(val, maxVal), minVal);
        valText = String.format(formatter, realVal);
        sweepAngle = (realVal -minVal) / valRange * (360 - (180 - pointerLineDegree) * 2);


        invalidate();
    }

    private int resolveMeasured(int measureSpec, int desired) {
        int specSize = MeasureSpec.getSize(measureSpec);
        int result;
        switch (MeasureSpec.getMode(measureSpec)) {
            case MeasureSpec.UNSPECIFIED:
                result = desired;
                break;
            case MeasureSpec.AT_MOST:
                result = Math.max(specSize, desired);
                break;
            case MeasureSpec.EXACTLY:
                result = specSize;
                break;
            default:
                result = specSize;
                break;
        }

        return result;
    }

    public void setValTextSize(float valTextSize) {
        this.valTextSize = valTextSize;
    }

    public void setValTextColor(int valTextColor) {
        this.valTextColor = valTextColor;
    }

    public void setLabelText(String labelText) {
        this.labelText = labelText;
    }

    public void setLabelTextSize(float labelTextSize) {
        this.labelTextSize = labelTextSize;
    }

    public void setLabelTextColor(int labelTextColor) {
        this.labelTextColor = labelTextColor;
    }

    public void setArcColor(int arcColor) {
        this.arcColor = arcColor;
    }
}
